package labox.innovation.gameserver.model;

import static labox.innovation.gameserver.model.itemcontainer.PcInventory.MAX_ADENA;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javolution.util.FastList;
import labox.innovation.config.Config;
import labox.innovation.gameserver.datatables.ItemTable;
import labox.innovation.gameserver.model.actor.instance.FuzePcInstance;
import labox.innovation.gameserver.model.itemcontainer.PcInventory;
import labox.innovation.gameserver.network.SystemMessageId;
import labox.innovation.gameserver.network.serverpackets.InventoryUpdate;
import labox.innovation.gameserver.network.serverpackets.ItemList;
import labox.innovation.gameserver.network.serverpackets.StatusUpdate;
import labox.innovation.gameserver.network.serverpackets.SystemMessage;
import labox.innovation.gameserver.network.serverpackets.TradeStats;
import labox.innovation.gameserver.templates.item.L2EtcItemType;
import labox.innovation.gameserver.templates.item.L2Item;

/**
 * @author Advi
 * 交易系统
 * 玩家 和 玩家的交易
 * 包括了 摆摊设置
 * 摆摊 暂不需要 ， 可以屏蔽 或 删除
 *
 */
public class TradeList {
	
	
	protected static final int MAX_ITEMS = 8;   //最大可 交易的物品数

	/**
	 * 交易的物品
	 * @author zjj
	 *
	 */
	public class TradeItem {
		private long _objectId;

		private final L2Item _item;

		private int _enchant;

		private int _type2;

		private int _count;

		private long _storeCount;

		private long _price;
		
		private int  _iconid;
		
		private String _name ;


		public TradeItem(L2ItemInstance item, int count, long price) {
			_objectId = item.getObjectId();
			_item = item.getItem();
			_enchant = item.getEnchantLevel();
			_type2 = item.getCustomType2();
			_iconid = item.getItem().getItemIconId();
			_count = count;
			_price = price;
			_name = item.getName();

		}

		public TradeItem(L2Item item, int count, long price) {
			_objectId = 0;
			_item = item;
			_enchant = 0;
			_type2 = 0;
			_count = count;
			_storeCount = count;
			_price = price;
			_iconid = item.getItemIconId();
			_name = item.getName();

		}

		public TradeItem(TradeItem item, int count, long price) {
			_objectId = item.getObjectId();
			_item = item.getItem();
			_enchant = item.getEnchant();
			_iconid = item.getIconId();
			_type2 = 0;
			_count = count;
			_storeCount = count;
			_price = price;
			_name = item.getName();

		}
		
		public String getName(){
			return _name;
		}
		
		public int getIconId()
		{
			return _iconid;
		}

		public void setObjectId(long objectId) {
			_objectId = objectId;
		}

		public long getObjectId() {
			return _objectId;
		}

		public L2Item getItem() {
			return _item;
		}

		public void setEnchant(int enchant) {
			_enchant = enchant;
		}

		public int getEnchant() {
			return _enchant;
		}

		public int getCustomType2() {
			return _type2;
		}

		public void setCount(int count) {
			_count = count;
		}

		public int getCount() {
			return _count;
		}

		public long getStoreCount() {
			return _storeCount;
		}

		public void setPrice(long price) {
			_price = price;
		}

		public long getPrice() {
			return _price;
		}

	}

	private static final Logger _log = LoggerFactory.getLogger(TradeList.class.getName());

	private final FuzePcInstance _owner;

	private FuzePcInstance _partner;

	private final List<TradeItem> _items;

	private String _title;

	private boolean _packaged;

	private boolean _confirmed = false;

	private boolean _locked = false;

	public TradeList(FuzePcInstance owner) {
		_items = new FastList<TradeItem>();
		_owner = owner;
	}

	public FuzePcInstance getOwner() {
		return _owner;
	}

	public void setPartner(FuzePcInstance partner) {
		_partner = partner;
	}

	public FuzePcInstance getPartner() {
		return _partner;
	}

	public void setTitle(String title) {
		_title = title;
	}

	public String getTitle() {
		return _title;
	}

	public boolean isLocked() {
		return _locked;
	}

	public boolean isConfirmed() {
		return _confirmed;
	}

	public boolean isPackaged() {
		return _packaged;
	}

	public void setPackaged(boolean value) {
		_packaged = value;
	}

	/**
	 * Retrieves items from TradeList
	 */
	public TradeItem[] getItems() {
		return _items.toArray(new TradeItem[_items.size()]);
	}

	/**
	 * Returns the list of items in inventory available for transaction
	 * @return L2ItemInstance : items in inventory
	 */
	public TradeList.TradeItem[] getAvailableItems(PcInventory inventory) {
		final List<TradeList.TradeItem> list = new FastList<TradeList.TradeItem>();
		for (TradeList.TradeItem item : _items) {
			item = new TradeItem(item, item.getCount(), item.getPrice());
			inventory.adjustAvailableItem(item);
			list.add(item);
		}

		return list.toArray(new TradeList.TradeItem[list.size()]);
	}

	/**
	 * Returns Item List size
	 */
	public int getItemCount() {
		return _items.size();
	}

	/**
	 * Adjust available item from Inventory by the one in this list
	 * @param item : L2ItemInstance to be adjusted
	 * @return TradeItem representing adjusted item
	 */
	public TradeItem adjustAvailableItem(L2ItemInstance item) {
		if (item.isStackable()) {
			for (TradeItem exclItem : _items) {
				if (exclItem.getItem().getItemId() == item.getItemId()) {
					if (item.getCount() <= exclItem.getCount())
						return null;
					else
						return new TradeItem(item, item.getCount() - exclItem.getCount(), item.getReferencePrice());
				}
			}
		}
		return new TradeItem(item, item.getCount(), item.getReferencePrice());
	}

	/**
	 * Adjust ItemRequest by corresponding item in this list using its <b>ObjectId</b>
	 * @param item : ItemRequest to be adjusted
	 */
	public void adjustItemRequest(ItemRequest item) {
		for (TradeItem filtItem : _items) {
			if (filtItem.getObjectId() == item.getObjectId()) {
				if (filtItem.getCount() < item.getCount())
					item.setCount(filtItem.getCount());
				return;
			}
		}
		item.setCount(0);
	}

	/**
	 * Add simplified item to TradeList
	 * 增加一个物品到 交易链中
	 * 增加物品到交易链中时 会检查物品是否可交易 ， 是否是任务物品等
	 * @param objectId : int 物品实例的唯一id
	 * @param count : int    物品数量
	 * @return
	 */
	public TradeItem addItem(long objectId, int count) {
		return addItem(objectId, count, 0);
	}

	/**
	 * Add simplified item to TradeList
	 * 增加一个物品到 交易链中
	 * 增加物品到交易链中时 会检查物品是否可交易 ， 是否是任务物品等
	 * 物品是否已加入到 交易链中
	 * @param objectId : int 物品实例的唯一id
	 * @param count : int    物品数量
	 * @return
	 */
	public TradeItem addItem(long objectId, int count, long price) {
//		if (isLocked()) {
//			_log.warning(_owner.getName() + ": Attempt to modify locked TradeList!");
//			return null;
//		}
		
		
		TradeItem titem = null;
		
		//物品是否已存在交易链 中 
		for (TradeItem checkitem : _items) {
//			if (checkitem.getObjectId() == objectId && !checkitem._item.isMoney())
//				return null;
//			else 
				if( checkitem.getObjectId() == objectId ){
				titem = checkitem;
				break;
			}
		}
		
		//物品不存在交易链中 且交易的物品数量 已到最大  不能在存放物品
		if( _items.size() >= MAX_ITEMS && titem == null )
		{
			//交易链已满  不能在存放
			return null;
		}
		

		L2Object o = FuzeWorld.getInstance().findObject(objectId);
//		System.out.println("对象是:" + o );
		if (!(o instanceof L2ItemInstance)) {
			_log.warn(_owner.getName() + ": Attempt to add invalid item to TradeList!" , Config.SERVER_ID, _owner.getName());
			return null;
		}

		L2ItemInstance item = (L2ItemInstance) o;
		int exCount = titem==null? 0 : titem.getCount();

		if (!(item.isTradeable() || (getOwner().isGM() && Config.GM_TRADE_RESTRICTED_ITEMS)) || item.getItemType() == L2EtcItemType.QUEST)
			return null;

		//如果数量为0 或者 添加物品的数量 大于物品本身拥有的数量， 那么不能添加
		if (count <= 0 || count > item.getCount())
			return null;

		//物品不能叠加， 数量大于1 不能添加
		if (!item.isStackable() && count > 1) {
			_log.warn( _owner.getName() + ": Attempt to add non-stackable item to TradeList with count > 1!", Config.SERVER_ID, _owner.getName());
			return null;
		}
	
		//物品是可叠加的， 且 叠加的数量 大于最大值 不能添加
		if( item.isStackable() && count + exCount > item.getItem().getMaxStackNums() )
		{
			_log.warn(_owner.getName() + "尝试增加的物品数 超过了物品可叠加的数" , Config.SERVER_ID, _owner.getName());
			return null;
		}

//		if ((PcInventory.MAX_ADENA / count) < price) {
//			_log.warn(_owner.getName() + ": Attempt to overflow adena !");
//			return null;
//		}

		if( titem == null ){
			titem = new TradeItem(item, count, price);
			_items.add(titem);
		}else{
			titem.setCount( count + exCount );
		}


		// If Player has already confirmed this trade, invalidate the confirmation
		invalidateConfirmation();
		
		unLock();
		TradeList temp = _partner.getActiveTradeList();
		if( temp != null )
		{
			temp.unLock();
			temp.invalidateConfirmation();
		}
		
		return titem;
	}

	/**
	 * 增加一个物品到 交易链中
	 * 增加物品到交易链中时 会检查物品是否可交易 ， 是否是任务物品等
	 * 
	 * @param itemId : 物品模板 id
	 * @param count : long
	 * @param price : long
	 * @return
	 */
	public TradeItem addItemByItemId(int itemId, int count, long price) {
		if (isLocked()) {
			_log.warn(_owner.getName() + ": Attempt to modify locked TradeList!", Config.SERVER_ID);
			return null;
		}

		L2Item item = ItemTable.getInstance().getTemplate(itemId);
		if (item == null) {
			_log.warn(_owner.getName() + ": Attempt to add invalid item to TradeList!", Config.SERVER_ID);
			return null;
		}

		if (!item.isTradeable() || item.getItemType() == L2EtcItemType.QUEST)
			return null;

		if (!item.isStackable() && count > 1) {
			_log.warn(_owner.getName() + ": Attempt to add non-stackable item to TradeList with count > 1!", Config.SERVER_ID);
			return null;
		}

		if ((PcInventory.MAX_ADENA / count) < price) {
			_log.warn(_owner.getName() + ": Attempt to overflow adena !", Config.SERVER_ID);
			return null;
		}

		TradeItem titem = new TradeItem(item, count, price);
		_items.add(titem);

		// If Player has already confirmed this trade, invalidate the confirmation
		invalidateConfirmation();
		return titem;
	}

	/**
	 * Remove item from TradeList
	 * 从物品交易链  移除一个物品
	 * @param objectId : int  物品唯一实例id
	 * @param count : int
	 * @return
	 */
	public TradeItem removeItem(long objectId, int itemId, int count) {
//		if (isLocked()) {
//			_log.warning(_owner.getName() + ": Attempt to modify locked TradeList!");
//			return null;
//		}
		unLock();

		for (TradeItem titem : _items) {
			if (titem.getObjectId() == objectId || titem.getItem().getItemId() == itemId) {
				// If Partner has already confirmed this trade, invalidate the confirmation
				if (_partner != null) {
					TradeList partnerList = _partner.getActiveTradeList();
					if (partnerList == null) {
						_log.warn(_partner.getName() + ": Trading partner (" + _partner.getName() + ") is invalid in this trade!", Config.SERVER_ID);
						return null;
					}
					partnerList.invalidateConfirmation();
				}

				// Reduce item count or complete item
				if (count != -1 && titem.getCount() > count)
					titem.setCount(titem.getCount() - count);
				else
					_items.remove(titem);

				return titem;
			}
		}
		return null;
	}

	/**
	 * Update items in TradeList according their quantity in owner inventory
	 * 根据 自己的背包 物品数量  更新物品数量
	 */
	public synchronized void updateItems() {
		for (TradeItem titem : _items) {
			L2ItemInstance item = _owner.getInventory().getItemByObjectId(titem.getObjectId());
			if (item == null || titem.getCount() < 1)
				removeItem(titem.getObjectId(), -1, -1);
			else if (item.getCount() < titem.getCount())
				titem.setCount(item.getCount());
		}
	}

	/**
	 * Lockes TradeList, no further changes are allowed
	 */
	public void lock() {
		_locked = true;
	}
	
	public void unLock()
	{
		_locked = false;
	}

	/**
	 * Clears item list
	 */
	public synchronized void clear() {
		_items.clear();
		_locked = false;
	}

	/**
	 * Confirms TradeList
	 * 确认物品交易
	 * @return : boolean
	 */
	public boolean confirm() {
		if (_confirmed)
			return true; // Already confirmed

		// If Partner has already confirmed this trade, proceed exchange
		if (_partner != null) {
			TradeList partnerList = _partner.getActiveTradeList();
			if (partnerList == null) {
				_log.warn(_partner.getName() + ": Trading partner (" + _partner.getName() + ") is invalid in this trade!", Config.SERVER_ID);
				return false;
			}

			// Synchronization order to avoid deadlock
			TradeList sync1, sync2;
			if (getOwner().getObjectId() > partnerList.getOwner().getObjectId()) {
				sync1 = partnerList;
				sync2 = this;
			} else {
				sync1 = this;
				sync2 = partnerList;
			}

			synchronized (sync1) {
				synchronized (sync2) {
					_confirmed = true;
					_owner.sendPacket(new TradeStats(TradeStats.STAT_IN_TRADE, TradeStats.STAT_SELF));
					if (partnerList.isConfirmed()) {
//						partnerList.lock();
//						lock();
						if (!partnerList.validate())
							return false;
						if (!validate())
							return false;

						doExchange(partnerList);
					} else
						_partner.onTradeConfirm(_owner);
				}
			}
		} else
			_confirmed = true;

		return _confirmed;
	}

	/**
	 * Cancels TradeList confirmation
	 */
	public void invalidateConfirmation() {
		_confirmed = false;
	}

	/**
	 * Validates TradeList with owner inventory
	 * 验证交易物品在玩家背包中 是否有效
	 */
	private boolean validate() {
		// Check for Owner validity
		if (_owner == null || FuzeWorld.getInstance().findObject(_owner.getObjectId()) == null) {
			_log.warn("Invalid owner of TradeList", Config.SERVER_ID);
			return false;
		}

		// Check for Item validity
		for (TradeItem titem : _items) {
			L2ItemInstance item = _owner.checkItemManipulation(titem.getObjectId(), titem.getCount(), "transfer");
			if (item == null || item.getCount() < 1) {
				_log.warn(_owner.getName() + ": Invalid Item in TradeList", Config.SERVER_ID);
				return false;
			}
		}

		return true;
	}

	/**
	 * Transfers all TradeItems from inventory to partner
	 * 把交易的物品 移到 目标对象中
	 */
	private boolean TransferItems(FuzePcInstance partner, InventoryUpdate ownerIU, InventoryUpdate partnerIU) {
//		_log.info("交易:" + getOwner().getName() + "(" + getOwner().getObjectId() + ")," +  partner.getName() + "(" + partner.getObjectId() + ");" )
		String str = "交易:" + getOwner().getName() + "(" + getOwner().getObjectId() + ")," +  partner.getName() + "(" + partner.getObjectId() + ");" ;
		for (TradeItem titem : _items){
			str += titem.getName() + "(" + titem.getObjectId() + ")," + titem.getCount() + ";";
		}
		
		_log.info( str, getOwner().getObjectId(), getOwner().getName() );
		
		for (TradeItem titem : _items) {
			L2ItemInstance oldItem = _owner.getInventory().getItemByObjectId(titem.getObjectId());
			if (oldItem == null)
				return false;
			L2ItemInstance newItem = _owner.getInventory().transferItem("交易:", titem.getObjectId(), titem.getCount(), partner.getInventory(), _owner, _partner);
			if (newItem == null)
				return false;

			// Add changes to inventory update packets
			if (ownerIU != null) {
				if (oldItem.getCount() > 0 && oldItem != newItem)
					ownerIU.addModifiedItem(oldItem);
				else
					ownerIU.addRemovedItem(oldItem);
			}

			if (partnerIU != null) {
				if (newItem.getCount() > titem.getCount())
					partnerIU.addModifiedItem(newItem);
				else
					partnerIU.addNewItem(newItem);
			}
		}
		
		return true;
		
	}

	/**
	 * Count items slots
	 * 计算 物品 所占的格子数
	 */
	public int countItemsSlots(FuzePcInstance partner) {
		int slots = 0;

		for (TradeItem item : _items) {
			if (item == null)
				continue;
			L2Item template = ItemTable.getInstance().getTemplate(item.getItem().getItemId());
			if (template == null)
				continue;
			//如果 物品不可以叠加 那么 所占格子数 为交易物品的数量
			if (!template.isStackable())
				slots += item.getCount();
			//如果物品 可以叠加 那么 如果目标对象中没有这个 物品 那么格子数 要增加
			else if (partner.getInventory().getItemByItemId(item.getItem().getItemId(), item.getCount()) == null)
				slots++;
		}

		return slots;
	}

	/**
	 * Proceeds with trade
	 * 处理  物品交换
	 */
	private void doExchange(TradeList partnerList) {
		boolean success = false;
		
		int mynums = partnerList.countItemsSlots(getOwner());  //对方交易给我的物品数
		int parternnums = countItemsSlots(partnerList.getOwner()); //我交易给对方的物品数

		// check weight and slots
	   if ((!getOwner().getInventory().validateCapacity(mynums - parternnums)) || (!partnerList.getOwner().getInventory().validateCapacity(parternnums - mynums))) {
			partnerList.getOwner().sendPacket(new SystemMessage(SystemMessageId.SLOTS_FULL));
			getOwner().sendPacket(new SystemMessage(SystemMessageId.SLOTS_FULL));
		} else {
			// Prepare inventory update packet
//			InventoryUpdate ownerIU = Config.FORCE_INVENTORY_UPDATE ? null : new InventoryUpdate();
//			InventoryUpdate partnerIU = Config.FORCE_INVENTORY_UPDATE ? null : new InventoryUpdate();

			InventoryUpdate ownerIU = null;
			InventoryUpdate partnerIU = null;
			
			//转移物品前，  先置空物品所占的位置
			TradeItem[] pitems = partnerList.getItems();
			for( TradeItem temp: pitems )
			{
				L2ItemInstance tItem = partnerList.getOwner().getInventory().getItemByObjectId(temp.getObjectId());
				if( tItem == null )
				{
					return;
				}
				
				partnerList.getOwner().getInventory().restInventorySlot( tItem.getLocationSlot() );
			}
			
			pitems = getItems();
			for( TradeItem temp: pitems )
			{
				L2ItemInstance tItem = getOwner().getInventory().getItemByObjectId(temp.getObjectId());
				if( tItem == null )
				{
					return;
				}
				
				getOwner().getInventory().restInventorySlot( tItem.getLocationSlot() );
			}
			//end
			
			// Transfer items
			partnerList.TransferItems(getOwner(), partnerIU, ownerIU);
			TransferItems(partnerList.getOwner(), ownerIU, partnerIU);

			// Send inventory update packet
			if (ownerIU != null)
				_owner.sendPacket(ownerIU);
			else
				_owner.sendPacket(new ItemList(_owner, false));

			if (partnerIU != null)
				_partner.sendPacket(partnerIU);
			else
				_partner.sendPacket(new ItemList(_partner, false));
			success = true;
		}
		// Finish the trade
		partnerList.getOwner().onTradeFinish(success);
		getOwner().onTradeFinish(success);
	}

	/**
	 * Buy items from this PrivateStore list
	 *  从私人商店 物品链 购买东西
	 *  类型 摆摊 功能
	 * @return : boolean true if success
	 */
	public synchronized boolean privateStoreBuy(FuzePcInstance player, ItemRequest[] items) {
		if (_locked)
			return false;

		if (!validate()) {
			lock();
			return false;
		}

		int slots = 0;

		int totalPrice = 0;

		final PcInventory ownerInventory = _owner.getInventory();
		final PcInventory playerInventory = player.getInventory();

		//查找 购买的物品 是否存在物品链中
		for (ItemRequest item : items) {
			boolean found = false;

			for (TradeItem ti : _items) {
				if (ti.getObjectId() == item.getObjectId()) {
					if (ti.getPrice() == item.getPrice()) {
						if (ti.getCount() < item.getCount())
							item.setCount(ti.getCount());
						found = true;
					}
					break;
				}
			}
			// item with this objectId and price not found in tradelist
			// 没有找到相应的物品 和 价格 那么继续查找下一个
			if (!found) {
				item.setCount(0);
				continue;
			}

			// check for overflow in the single item
			// 检查单个物品的 价格 是否已 溢出
			if ((MAX_ADENA / item.getCount()) < item.getPrice()) {
				// private store attempting to overflow - disable it
				lock();
				return false;
			}

			//计算总价格
			totalPrice += item.getCount() * item.getPrice();
			// check for overflow of the total price
			// 检查 总价格是否溢出
			if (MAX_ADENA < totalPrice || totalPrice < 0) {
				// private store attempting to overflow - disable it
				lock();
				return false;
			}

			// Check if requested item is available for manipulation
			// 检查交易的物品 是否能有效的被交易
			L2ItemInstance oldItem = _owner.checkItemManipulation(item.getObjectId(), item.getCount(), "sell");
			if (oldItem == null || !oldItem.isTradeable()) {
				// private store sell invalid item - disable it
				lock();
				return false;
			}

			L2Item template = ItemTable.getInstance().getTemplate(item.getItemId());
			if (template == null)
				continue;

			//所占用 的格子数
			if (!template.isStackable())
				slots += item.getCount();
			else if (playerInventory.getItemByItemId(item.getItemId()) == null)
				slots++;
			
		}// end for (ItemRequest item : items)

		//检查 买物品玩家的 钱是否够
		if (totalPrice > playerInventory.getMoneySilver()) {
			player.sendPacket(new SystemMessage(SystemMessageId.YOU_NOT_ENOUGH_ADENA));
			return false;
		}

		//检查购买玩家的 背包容量是否够
		if (!playerInventory.validateCapacity(slots)) {
			player.sendPacket(new SystemMessage(SystemMessageId.SLOTS_FULL));
			return false;
		}

		// Prepare inventory update packets
		final InventoryUpdate ownerIU = new InventoryUpdate();
		final InventoryUpdate playerIU = new InventoryUpdate();

		final L2ItemInstance adenaItem = playerInventory.getMoneySilverInstance();
		playerInventory.reduceMoneySilver("PrivateStore", totalPrice, player, _owner);
		playerIU.addItem(adenaItem);
		ownerInventory.addMoneySilver("PrivateStore", totalPrice, _owner, player);
		ownerIU.addItem(ownerInventory.getMoneySilverInstance());

		//转移物品是否完全成功
		boolean ok = true;

		// Transfer items
		// 转移物品 到玩家背包中去
		for (ItemRequest item : items) {
			if (item.getCount() == 0)
				continue;

			// Check if requested item is available for manipulation
			// 检查物品 是否能被交易
			L2ItemInstance oldItem = _owner.checkItemManipulation(item.getObjectId(), item.getCount(), "sell");
			if (oldItem == null) {
				// should not happens - validation already done
				lock();
				ok = false;
				break;
			}

			// Proceed with item transfer
			// 开始转移物品
			L2ItemInstance newItem = ownerInventory.transferItem("PrivateStore", item.getObjectId(), item.getCount(), playerInventory, _owner, player);
			if (newItem == null) {
				//转移失败
				ok = false;
				break;
			}
			
			//从物品 交易链中 去掉一个物品
			removeItem(item.getObjectId(), -1, item.getCount());

			// Add changes to inventory update packets
			// 增加背包更新消息
			if (oldItem.getCount() > 0 && oldItem != newItem)
				ownerIU.addModifiedItem(oldItem);
			else
				ownerIU.addRemovedItem(oldItem);
			if (newItem.getCount() > item.getCount())
				playerIU.addModifiedItem(newItem);
			else
				playerIU.addNewItem(newItem);

			// Send messages about the transaction to both players
			// 给参与交易的双方 发送信息
			if (newItem.isStackable()) {
				SystemMessage msg = new SystemMessage(SystemMessageId.C1_PURCHASED_S3_S2_S);
				msg.addString(player.getName());
				msg.addItemName(newItem);
				msg.addItemNumber(item.getCount());
				_owner.sendPacket(msg);

				msg = new SystemMessage(SystemMessageId.PURCHASED_S3_S2_S_FROM_C1);
				msg.addString(_owner.getName());
				msg.addItemName(newItem);
				msg.addItemNumber(item.getCount());
				player.sendPacket(msg);
			} else {
				SystemMessage msg = new SystemMessage(SystemMessageId.C1_PURCHASED_S2);
				msg.addString(player.getName());
				msg.addItemName(newItem);
				_owner.sendPacket(msg);

				msg = new SystemMessage(SystemMessageId.PURCHASED_S2_FROM_C1);
				msg.addString(_owner.getName());
				msg.addItemName(newItem);
				player.sendPacket(msg);
				
			}// end if (newItem.isStackable())
			
		}// end 	for (ItemRequest item : items)

		// Send inventory update packet
		_owner.sendPacket(ownerIU);
		player.sendPacket(playerIU);
		return ok;
	}

	/**
	 * Sell items to this PrivateStore list
	 * 在私人商店 卖物品
	 * 
	 * @return : boolean true if success
	 */
	public synchronized boolean privateStoreSell(FuzePcInstance player, ItemRequest[] items) {
		if (_locked)
			return false;

		boolean ok = false;

		final PcInventory ownerInventory = _owner.getInventory();
		final PcInventory playerInventory = player.getInventory();

		// Prepare inventory update packet
		final InventoryUpdate ownerIU = new InventoryUpdate();
		final InventoryUpdate playerIU = new InventoryUpdate();

		int totalPrice = 0;

		for (ItemRequest item : items) {
			// searching item in tradelist using itemId
			boolean found = false;

			for (TradeItem ti : _items) {
				if (ti.getItem().getItemId() == item.getItemId()) {
					// price should be the same
					if (ti.getPrice() == item.getPrice()) {
						// if requesting more than available - decrease count
						if (ti.getCount() < item.getCount())
							item.setCount(ti.getCount());
						found = item.getCount() > 0;
					}
					break;
				}
			}
			// not found any item in the tradelist with same itemId and price
			// maybe another player already sold this item ?
			if (!found)
				continue;

			// check for overflow in the single item
			if ((MAX_ADENA / item.getCount()) < item.getPrice()) {
				lock();
				break;
			}

			int _totalPrice = totalPrice + item.getCount() * item.getPrice();
			// check for overflow of the total price
			if (MAX_ADENA < _totalPrice || _totalPrice < 0) {
				lock();
				break;
			}

			if (ownerInventory.getMoneySilver() < _totalPrice)
				continue;

			// Check if requested item is available for manipulation
			long objectId = item.getObjectId();
			L2ItemInstance oldItem = player.checkItemManipulation(objectId, item.getCount(), "sell");
			// private store - buy use same objectId for buying several non-stackable items
			if (oldItem == null) {
				// searching other items using same itemId
				oldItem = playerInventory.getItemByItemId(item.getItemId());
				if (oldItem == null)
					continue;
				objectId = oldItem.getObjectId();
				oldItem = player.checkItemManipulation(objectId, item.getCount(), "sell");
				if (oldItem == null)
					continue;
			}

			if (!oldItem.isTradeable())
				continue;

			// Proceed with item transfer
			L2ItemInstance newItem = playerInventory.transferItem("PrivateStore", objectId, item.getCount(), ownerInventory, player, _owner);
			if (newItem == null)
				continue;

			removeItem(-1, item.getItemId(), item.getCount());
			ok = true;

			// increase total price only after successful transaction
			totalPrice = _totalPrice;

			// Add changes to inventory update packets
			if (oldItem.getCount() > 0 && oldItem != newItem)
				playerIU.addModifiedItem(oldItem);
			else
				playerIU.addRemovedItem(oldItem);
			if (newItem.getCount() > item.getCount())
				ownerIU.addModifiedItem(newItem);
			else
				ownerIU.addNewItem(newItem);

			// Send messages about the transaction to both players
			if (newItem.isStackable()) {
				SystemMessage msg = new SystemMessage(SystemMessageId.PURCHASED_S3_S2_S_FROM_C1);
				msg.addString(player.getName());
				msg.addItemName(newItem);
				msg.addItemNumber(item.getCount());
				_owner.sendPacket(msg);

				msg = new SystemMessage(SystemMessageId.C1_PURCHASED_S3_S2_S);
				msg.addString(_owner.getName());
				msg.addItemName(newItem);
				msg.addItemNumber(item.getCount());
				player.sendPacket(msg);
			} else {
				SystemMessage msg = new SystemMessage(SystemMessageId.PURCHASED_S2_FROM_C1);
				msg.addString(player.getName());
				msg.addItemName(newItem);
				_owner.sendPacket(msg);

				msg = new SystemMessage(SystemMessageId.C1_PURCHASED_S2);
				msg.addString(_owner.getName());
				msg.addItemName(newItem);
				player.sendPacket(msg);
			}
		}

		if (totalPrice > 0) {
			// Transfer adena
			if (totalPrice > ownerInventory.getMoneySilver())
				// should not happens, just a precaution
				return false;
			final L2ItemInstance adenaItem = ownerInventory.getMoneySilverInstance();
			ownerInventory.reduceMoneySilver("PrivateStore", totalPrice, _owner, player);
			ownerIU.addItem(adenaItem);
			playerInventory.addMoneySilver("PrivateStore", totalPrice, player, _owner);
			playerIU.addItem(playerInventory.getMoneySilverInstance());
		}

		if (ok) {
			// Send inventory update packet
			_owner.sendPacket(ownerIU);
			player.sendPacket(playerIU);
		}
		return ok;
	}
}
